#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "mailbox.h"
#include "msg_manager.h"
#include "task_manager.h"
#include "esp_log.h"
#include "esp_err.h"

#define TAG "MSG_MANAGER"

bool msg_manager_send_async_msg(char* receiver, struct app_msg *msg)
{
    TaskHandle_t* receiver_task = task_manager_get_handle(receiver);
    if (receiver_task == NULL) {
        ESP_LOGE(TAG, "Receiver task not found");
        return false;
    }
    mailbox_send_to_task(msg, *receiver_task, 0);

    return true;
}

bool msg_manager_send_sync_msg(char *receiver, struct app_msg *msg, struct app_msg **response)
{
    TaskHandle_t* receiver_task = task_manager_get_handle(receiver);
    if (receiver_task == NULL) {
        ESP_LOGE(TAG, "Receiver task %s not found", receiver);
        if (msg->reserve == RESERVE_PTR && msg->ptr) {
            free(msg->ptr);
        }
        return false;
    }
    esp_err_t ret = mailbox_rpc_call(msg, *receiver_task, response, portMAX_DELAY);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "RPC call to %s failed: %s", receiver, esp_err_to_name(ret));
        if (msg->reserve == RESERVE_PTR && msg->ptr) {
            free(msg->ptr);
        }
        return false;
    }
    return true;
}

bool msg_manager_receive_msg(struct app_msg** msg, int timeout)
{
    mailbox_entry_t* entry = find_mailbox_entry(xTaskGetCurrentTaskHandle());
    if (entry == NULL) {
        ESP_LOGE(TAG, "No mailbox entry found for current task");
        return false;
    }
    if (xQueueReceive(entry->msg_queue, msg, timeout) == pdTRUE) {
        return true;
    }
    return false;
}

bool msg_manager_receive_exit(struct app_msg *msg)
{
    if (msg == NULL) {
        ESP_LOGE(TAG, "Null message received");
        return false;
    }
    if (msg->callback) {
        msg->callback(msg);
    }
    mailbox_response_or_free(msg);
    return true;
}

bool msg_manager_init(void)
{
    mailbox_register_current_task();
    return true;
}

bool msg_manager_deinit(void)
{
    mailbox_unregister_task(xTaskGetCurrentTaskHandle());
    return true;
}